package com.tianji.learning.jobs;


import com.tianji.common.utils.CollUtils;
import com.tianji.learning.constants.LearningConstants;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.po.PointsBoardSeason;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.IPointsBoardService;
import com.tianji.learning.utils.TableInfoContext;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

//@Component
@Slf4j
@RequiredArgsConstructor
public class PointsBoardPersistentHandler2 {
    private final IPointsBoardSeasonService iPointsBoardSeasonService;
    private final IPointsBoardService boardService;

    private final StringRedisTemplate redisTemplate;

    @XxlJob("createTableJob")
    public void createTableJob() {
        //1.获取上个月的时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        PointsBoardSeason sesson = iPointsBoardSeasonService.lambdaQuery()
                .le(PointsBoardSeason::getBeginTime, time)
                .ge(PointsBoardSeason::getEndTime, time)
                .one();
        if (sesson == null) {
            return;
        }
        //创建表名
        boardService.createPointBoardTableBySesson(LearningConstants.POINTS_BOARD_TABLE_PREFIX + sesson.getId());
    }

    @XxlJob("savePointsBoard2DB")
    public void savePointsBoard2DB() {
        //1.获取上个月的时间
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        PointsBoardSeason sesson = iPointsBoardSeasonService.lambdaQuery()
                .le(PointsBoardSeason::getBeginTime, time)
                .ge(PointsBoardSeason::getEndTime, time)
                .one();
        if (sesson == null) {
            return;
        }
        //拼接表名
        String TableName = LearningConstants.POINTS_BOARD_TABLE_PREFIX + sesson.getId();
        TableInfoContext.setInfo(TableName);
        //查询redis里面的key
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + time.format(DateTimeFormatter.ofPattern("yyyyMM"));
        int pageNo = 1;
        int pageSize = 100;
        while (true) {
            List<PointsBoard> boardsList = queryCurrentBoardList(key, pageNo, pageSize);
            //如果redis娶完了
            if (CollUtils.isEmpty(boardsList)) {
                break;
            }
            //持久化
            boardsList.forEach(b -> {
                b.setId(b.getRank().longValue());//id做成
                b.setRank(null);
            });
            boardService.saveBatch(boardsList);
            pageNo++;
        }

        TableInfoContext.remove();
    }

    @XxlJob("clearPointBoardFromRedis")
    public void clearPointBoardFromRedis() {
        LocalDateTime time = LocalDateTime.now().minusMonths(1);
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + time.format(DateTimeFormatter.ofPattern("yyyyMM"));
        //3.使用unlike删除
        redisTemplate.unlink(key);
    }

    private List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {

        //1.计算start 和 end
        int start = (pageNo - 1) * pageSize;
        int end = start + pageSize - 1;
        //2.从Redis查询 ZREVRANGE Key start stop [WITHSCORES]
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
        if (CollUtils.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }
        //3.封装List<PointsBoard>
        List<PointsBoard> pointsBoardLists = new ArrayList<>();
        int rank = start + 1;
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            //每遍历一次对象返回一个PointsBoard对象
            PointsBoard po = new PointsBoard();
            String userId = tuple.getValue();
            Double score = tuple.getScore();
            if (userId == null || score == null) {
                continue;
            }

            //封装
            po.setUserId(Long.valueOf(userId));
            po.setPoints(score.intValue());
            po.setRank(rank);
            rank++;
            pointsBoardLists.add(po);
        }
        return pointsBoardLists;
    }

}
